
#pragma once

#include "Variant_types.h"

#if defined(__GNUC__) || defined(__MINGW32__) || defined(__MINGW__)
    #pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Weffc++"
    #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
#endif


namespace tools
{
//    struct Variant;
    struct IVariantScanner;
    void Scan(IVariantScanner&, const Variant&);

    variant_detail::VariantTypes::Str ToStruct(const Variant&);
    variant_detail::VariantTypes::Str ToPythonStyle(const Variant&);
    variant_detail::VariantTypes::Str ToHummanStyle(const Variant&);
    
    struct IVariantScanner: variant_detail::VariantTypes
    {

        friend void Scan(IVariantScanner&, const Variant&);
        IVariantScanner():mLeaving(false),mError(false),mStop(false){}
        virtual ~IVariantScanner(){}
    protected:
        // вызывается, если сканнер зафиксировал какую то неисправность
        virtual void Invalid(const Variant&){}

        // вызывается перед началом сканирования
        virtual void Begin(const Variant&){}

        // вызывается по окончанию сканирования
        virtual void End(const Variant&){}

        // вызывается если встретился контейнер
        virtual bool Container(const Variant&, const Str&){ return false; }

        // вызывается если встретился примитивный тип данных
        virtual void Primitive(const Variant&, const Str&){}

        // вызывается перед тем, как зайти во вложенный контейнер
        virtual void EnterContainer(const Variant&, const Str&){}
        
        // вызывается перед тем, как выйти из вложенного контейнера
        virtual void LeaveContainer(const Variant&, const Str&){}

        // была ли придутильная остановка сканирования?
        bool Stopped()const{ return mStop; }

        // нужно ли покинуть текущий контейнер и вернуться в родительский?
        bool NeedToLeave()const{ return mLeaving; }

        // была ли поломка контейнера?
        bool IsBroken()const { return mError; }
    protected:
        void Stop()   { mStop    = true; }
        void Leave()  { mLeaving = true; }
        void Broken() {  mError=true;    }
    private:
        bool NeedLeave()
        {
            const bool leave = mLeaving;
            return (mLeaving = false, leave);
        }
    private:
        bool mLeaving, mError, mStop;
    };
    

}//namespace tools


#if defined(__GNUC__) || defined(__MINGW32__) || defined(__MINGW__)
    #pragma GCC diagnostic pop
#endif
